package hydrap2p.modulemanager;

import hydrap2p.helper.Utility;

import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.dtools.ini.AdvancedIniFile;
import org.dtools.ini.AdvancedIniSection;
import org.dtools.ini.IniFile;
import org.dtools.ini.IniFileReader;
import org.dtools.ini.IniFileWriter;
import org.dtools.ini.IniItem;
import org.dtools.ini.IniSection;

public class ConfigMunger {
	
	private String sharedConfDir;
	private String userConfDir;
	
	public ConfigMunger()
	{
		sharedConfDir=Utility.appendPath(Utility.getSharedConfigurationPath(),"modules");
		userConfDir=Utility.appendPath(Utility.getUserConfigurationPath(),"modules");
	}
	
	public Map<String, ModuleConfig> load()
	{
		Map<String,ModuleConfig> ret;
		
		ret=loadConfDir(new File(sharedConfDir));		// shared config
		ret.putAll(loadConfDir(new File(userConfDir)));	// user config overrides
		
		buildDepends(ret);
		
		return ret;
	}
	
	public Map<String,ModuleConfig> loadConfDir(File confdir)
	{
		Map<String,ModuleConfig> conf=new TreeMap<String,ModuleConfig>();
		if (!confdir.isDirectory())
			return conf;
		for (File conffile:confdir.listFiles())
		{
			if (conffile.isDirectory())
				continue;
			if (!conffile.getPath().toLowerCase().endsWith(".ini"))
				continue;
			
			IniFile reader = new AdvancedIniFile();
			try {
				new IniFileReader(reader,conffile).read();
			} catch (IOException e) {
				// Could not read the file
				continue;
			}
			
			for (IniSection section:reader.getSections())
			{
				if (conf.containsKey(section.getName()))
				{
					System.err.println("Warning: Duplicate module definition for "+section.getName()+" found in "+conffile.getAbsolutePath());
					continue;
				}
				
				ModuleConfig temp=new ModuleConfig();
				temp.where=conffile;
				temp.name=section.getName();
				if (section.getItem("autostart")!=null)
					temp.autostart=Boolean.parseBoolean(section.getItem("autostart").getValue());
				if (section.getItem("control")!=null)
					temp.control=section.getItem("control").getValue();
				
				if (section.getItem("command")!=null)
				{
					IniItem temp2=section.getItem("command");
					temp.command=temp2.getValue();
					if (!temp2.getEndLineComment().isEmpty())
						temp.command=temp.command+IniItem.COMMENT_SYMBOL+temp2.getEndLineComment();
					temp.realcommand=expandModuleCommand(temp.command);
				}
				if (temp.name!=null && temp.command!=null)
				{
					conf.put(section.getName(), temp);
					
					if (section.getItem("depends")!=null)
					{
						String strdependencies = section.getItem("depends").getValue();
						String[] dependencies=strdependencies.split(",");
						for (String dependency : dependencies)
						{
							if (!dependency.trim().isEmpty())
								temp.needs.add(dependency.trim());
						}
					}
					
					if (section.getItem("provides")!=null)
					{
						String strservices = section.getItem("provides").getValue();
						String[] services=strservices.split(",");
						for (String service : services)
						{
							if (!service.trim().isEmpty())
								temp.services.add(service.trim());
						}
					}
				}
				
			}
		}	
		return conf;
	}

	private static String expandModuleCommand(String command)
	{
		String temp=command;
		
		// automatically expand lib/*
		File directory=new File("lib");
		if (directory.exists())
		{
			StringBuilder filelist=new StringBuilder();
			String[] files=directory.list();
			for (String file:files)
			{
				if (file.toLowerCase().endsWith(".jar"))
					filelist.append("|lib/"+file);
			}
			temp=temp.replaceAll("\\|lib/\\*", filelist.toString());
		}
		else
		{
			System.err.println("Could not find directory "+directory.getAbsolutePath());
		}

		// Change | in classpath to : or ; depending on OS
		if (System.getProperty("os.name").toLowerCase().indexOf("win")>=0)
		{
			temp=temp.replace('|',';');
		}
		else
		{
			temp=temp.replace('|', ':');
		}

		return temp;
	}
	
	private static List<ModuleConfig> getProvidedBy(Map<String, ModuleConfig> confs, String service)
	{
		List<ModuleConfig> modules=new LinkedList<ModuleConfig>();
		for (ModuleConfig conf : confs.values())
		{
			if (conf.services.contains(service))
				modules.add(conf); 
		}
		return modules;
	}
	
	private static void buildDepends(Map<String, ModuleConfig> confs)
	{
		for (ModuleConfig conf:confs.values())
		{
			for (String needing : conf.needs)
			{
				List<ModuleConfig> provides=getProvidedBy(confs, needing);
				for (ModuleConfig providing : provides)
					providing.neededby.add(conf.name);
			}
		}
	}

	public void updateUserConf(ModuleConfig conf)
	{
		File where=conf.where;
		IniFile output=new AdvancedIniFile();

		String filename=conf.where.getName();
		where=new File(Utility.appendPath(userConfDir, filename));
		where.getParentFile().mkdirs();
		if (where.isFile())
		{
			try {
				new IniFileReader(output,where).read();
			} catch (IOException e) {
				// TODO give some logging about why the conf didn't get loaded
			}
		}
		
		IniSection section=output.getSection(conf.name);
		if (section==null)
			section=new AdvancedIniSection(conf.name);
		IniItem temp;
		temp=section.getItem("autostart");
		if (temp==null)
			temp=new IniItem("autostart");
		temp.setValue(conf.autostart);
		section.removeItem("autostart");
		section.addItem(temp);
				
		temp=section.getItem("command");
		if (temp==null)
			temp=new IniItem("command");
		temp.setValue(conf.command);
		section.removeItem("command");
		section.addItem(temp);
		
		temp=section.getItem("control");
		if (temp==null)
			temp=new IniItem("control");
		temp.setValue(conf.control);
		section.removeItem("control");
		section.addItem(temp);
		
		temp=section.getItem("depends");
		if (temp==null)
		{
			temp=new IniItem("depends");
			section.addItem(temp);
		}
		
		temp=section.getItem("services");
		if (temp==null)
		{
			temp=new IniItem("services");
			section.addItem(temp);
		}
		
		try {
			output.addSection(section);
			new IniFileWriter(output,where).write();
		} catch (IOException e) {
			// TODO give some logging about why the conf didn't get saved
		}
	}
	
}
